dragicon: Add gtk_drag_icon_create_widget_for_value()
authorBenjamin Otte <otte@redhat.com>
Mon, 2 Mar 2020 02:11:14 +0000 (03:11 +0100)
committerBenjamin Otte <otte@redhat.com>
Mon, 2 Mar 2020 03:43:56 +0000 (04:43 +0100)
... and use it to set a drag icon.

docs/reference/gtk/gtk4-sections.txt
gtk/gtkdragicon.c
gtk/gtkdragicon.h
gtk/gtkdragsource.c

index 419b28193c6e46f978f90ead17f89318355e8506..689ac2b02475a96ce8ff2f665e086c5af4415306 100644 (file)
@@ -6885,6 +6885,9 @@ gtk_drag_icon_set_child
 gtk_drag_icon_get_child
 gtk_drag_icon_set_from_paintable
 
+<SUBSECTION>
+gtk_drag_icon_create_widget_for_value
+
 <SUBSECTION Standard>
 GTK_TYPE_DRAG_ICON
 GTK_DRAG_ICON
index 4e1afa522aeb18ddba73fa08110eec387ee1dbea..a01e088946c04dac07658d458bf44aaa8d982579 100644 (file)
 #include "gtkpicture.h"
 #include "gtkcssnumbervalueprivate.h"
 
+/* for the drag icons */
+#include "gtkcolorswatchprivate.h"
+#include "gtklabel.h"
+#include "gtktextutil.h"
+
 
 /**
  * SECTION:gtkdragicon
@@ -497,3 +502,62 @@ gtk_drag_icon_get_child (GtkDragIcon *self)
   return self->child;
 }
 
+/**
+ * gtk_drag_icon_create_widget_for_value:
+ * @value: a #GValue
+ *
+ * Creates a widget that can be used as a drag icon for the given
+ * @value.
+ *
+ * If GTK does not know how to create a widget for a given value,
+ * it will return %NULL.
+ *
+ * This method is used to set the default drag icon on drag'n'drop
+ * operations started by #GtkDragSource, so you don't need to set
+ * a drag icon using this function there.
+ *
+ * Returns: (nullable) (transfer full): A new #GtkWidget
+ *     for displaying @value as a drag icon.
+ **/
+GtkWidget *
+gtk_drag_icon_create_widget_for_value (const GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE (value), NULL);
+
+  if (G_VALUE_HOLDS (value, G_TYPE_STRING))
+    {
+      return gtk_label_new (g_value_get_string (value));
+    }
+  else if (G_VALUE_HOLDS (value, GDK_TYPE_RGBA))
+    {
+      GtkWidget *swatch;
+
+      swatch = gtk_color_swatch_new ();
+      gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (swatch), g_value_get_boxed (value));
+
+      return swatch;
+    }
+  else if (G_VALUE_HOLDS (value, GTK_TYPE_TEXT_BUFFER))
+    {
+      GtkTextBuffer *buffer = g_value_get_object (value);
+      GtkTextIter start, end;
+      GdkPaintable *paintable;
+      GtkWidget *picture;
+
+      if (buffer == NULL || !gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+        return NULL;
+
+      picture = gtk_picture_new ();
+      paintable = gtk_text_util_create_rich_drag_icon (picture, buffer, &start, &end);
+      gtk_picture_set_paintable (GTK_PICTURE (picture), paintable);
+      gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
+      g_object_unref (paintable);
+
+      return picture;
+    }
+  else
+    {
+      return NULL;
+    }
+}
+
index b8c70d6f869d39be68af89f46f3a521ff54b0084..3be995773a8158dce67d13784bee43a8af301809 100644 (file)
@@ -52,6 +52,8 @@ void            gtk_drag_icon_set_from_paintable (GdkDrag      *drag,
                                                   int           hot_x,
                                                   int           hot_y);
 
+GtkWidget *     gtk_drag_icon_create_widget_for_value           (const GValue           *value);
+
 G_END_DECLS
 
 
index 6b6c4d38de094977b734b6b17ea30da496e9ec5f..017bee493c91438ce10a97b3f95aca418b4b3343 100644 (file)
@@ -439,6 +439,52 @@ gtk_drag_source_cancel_cb (GdkDrag             *drag,
   drag_end (source, FALSE);
 }
 
+static void
+gtk_drag_source_ensure_icon (GtkDragSource *self,
+                             GdkDrag       *drag)
+{
+  GdkContentProvider *provider;
+  GtkWidget *icon, *child;
+  GdkContentFormats *formats;
+  const GType *types;
+  gsize i, n_types;
+
+  icon = gtk_drag_icon_get_for_drag (drag);
+  /* If an icon has been set already, we don't need to set one. */
+  if (gtk_drag_icon_get_child (GTK_DRAG_ICON (icon)))
+    return;
+
+  gdk_drag_set_hotspot (drag, -2, -2);
+
+  provider = gdk_drag_get_content (drag);
+  formats = gdk_content_provider_ref_formats (provider);
+  types = gdk_content_formats_get_gtypes (formats, &n_types);
+  for (i = 0; i < n_types; i++)
+    {
+      GValue value = G_VALUE_INIT;
+
+      g_value_init (&value, types[i]);
+      if (gdk_content_provider_get_value (provider, &value, NULL))
+        {
+          child = gtk_drag_icon_create_widget_for_value (&value);
+
+          if (child)
+            {
+              gtk_drag_icon_set_child (GTK_DRAG_ICON (icon), child);
+              g_value_unset (&value);
+              gdk_content_formats_unref (formats);
+              return;
+            }
+        }
+      g_value_unset (&value);
+    }
+
+  gdk_content_formats_unref (formats);
+  child = gtk_image_new_from_icon_name ("text-x-generic");
+  gtk_image_set_icon_size (GTK_IMAGE (child), GTK_ICON_SIZE_LARGE);
+  gtk_drag_icon_set_child (GTK_DRAG_ICON (icon), child);
+}
+
 static void
 gtk_drag_source_drag_begin (GtkDragSource *source)
 {
@@ -481,23 +527,7 @@ gtk_drag_source_drag_begin (GtkDragSource *source)
 
   g_signal_emit (source, signals[DRAG_BEGIN], 0, source->drag);
 
-  if (!source->paintable)
-    {
-      GtkIconTheme *theme;
-
-      theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (widget));
-      source->paintable = GDK_PAINTABLE(gtk_icon_theme_lookup_icon (theme,
-                                                                    "text-x-generic",
-                                                                    NULL,
-                                                                    32,
-                                                                    1,
-                                                                    gtk_widget_get_direction (widget),
-                                                                    0));
-      source->hot_x = 0;
-      source->hot_y = 0;
-    }
-
-  gtk_drag_icon_set_from_paintable (source->drag, source->paintable, source->hot_x, source->hot_y);
+  gtk_drag_source_ensure_icon (source, source->drag);
 
   g_signal_connect (source->drag, "dnd-finished",
                     G_CALLBACK (gtk_drag_source_dnd_finished_cb), source);